{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 为用户推荐好友"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入包\n",
    "import random\n",
    "import math\n",
    "import time\n",
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一. 通用函数定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义装饰器，监控运行时间\n",
    "def timmer(func):\n",
    "    def wrapper(*args, **kwargs):\n",
    "        start_time = time.time()\n",
    "        res = func(*args, **kwargs)\n",
    "        stop_time = time.time()\n",
    "        print('Func %s, run time: %s' % (func.__name__, stop_time - start_time))\n",
    "        return res\n",
    "    return wrapper"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 数据处理相关\n",
    "1. load data\n",
    "2. split data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dataset():\n",
    "    \n",
    "    def __init__(self, fp, sample=100000):\n",
    "        # fp: data file path\n",
    "        # sample: 只取部分数据集，-1则为全部\n",
    "        self.data = self.loadData(fp, sample)\n",
    "    \n",
    "    def loadData(self, fp, sample):\n",
    "        # 只取一个小数据集进行处理\n",
    "        data = [f.strip().split('\\t') for f in open(fp).readlines()[4:]]\n",
    "        if sample == -1: \n",
    "            return data\n",
    "        else:\n",
    "            random.shuffle(data)\n",
    "            return data[:sample]\n",
    "    \n",
    "    def splitData(self, M, k, seed=1):\n",
    "        '''\n",
    "        :params: data, 加载的所有(user, item)数据条目\n",
    "        :params: M, 划分的数目，最后需要取M折的平均\n",
    "        :params: k, 本次是第几次划分，k~[0, M)\n",
    "        :params: seed, random的种子数，对于不同的k应设置成一样的\n",
    "        :return: train, test\n",
    "        '''\n",
    "        train, test = [], []\n",
    "        random.seed(seed)\n",
    "        for u, v in self.data:\n",
    "            # 这里与书中的不一致，本人认为取M-1较为合理，因randint是左右都覆盖的\n",
    "            if random.randint(0, M-1) == k:  \n",
    "                test.append((u, v))\n",
    "            else:\n",
    "                train.append((u, v))\n",
    "\n",
    "        # 处理成字典的形式，user->set(items)\n",
    "        def convert_dict(data):\n",
    "            data_dict = {} # 当前用户指向的用户\n",
    "            data_dict_t = {} # 指向当前用户的用户\n",
    "            for u, v in data:\n",
    "                if u not in data_dict:\n",
    "                    data_dict[u] = set()\n",
    "                data_dict[u].add(v)\n",
    "                if v not in data_dict_t:\n",
    "                    data_dict_t[v] = set()\n",
    "                data_dict_t[v].add(u)\n",
    "            data_dict = {k: list(data_dict[k]) for k in data_dict}\n",
    "            data_dict_t = {k: list(data_dict_t[k]) for k in data_dict_t}\n",
    "            return data_dict, data_dict_t\n",
    "\n",
    "        return convert_dict(train), convert_dict(test)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 评价指标\n",
    "1. Precision\n",
    "2. Recall\n",
    "3. Coverage\n",
    "4. Popularity(Novelty)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Metric():\n",
    "    \n",
    "    def __init__(self, train, test, GetRecommendation):\n",
    "        '''\n",
    "        :params: train, 训练数据\n",
    "        :params: test, 测试数据\n",
    "        :params: GetRecommendation, 为某个用户获取推荐物品的接口函数\n",
    "        '''\n",
    "        self.train = train\n",
    "        self.test = test\n",
    "        self.GetRecommendation = GetRecommendation\n",
    "        self.recs = self.getRec()\n",
    "        \n",
    "    # 为test中的每个用户进行推荐\n",
    "    def getRec(self):\n",
    "        recs = {}\n",
    "        for user in self.test:\n",
    "            rank = self.GetRecommendation(user)\n",
    "            recs[user] = rank\n",
    "        return recs\n",
    "        \n",
    "    # 定义精确率指标计算方式\n",
    "    def precision(self):\n",
    "        all, hit = 0, 0\n",
    "        for user in self.test:\n",
    "            test_users = set(self.test[user])\n",
    "            rank = self.recs[user]\n",
    "            for v, score in rank:\n",
    "                if v in test_users:\n",
    "                    hit += 1\n",
    "            all += len(rank)\n",
    "        return round(hit / all * 100, 2) if all > 0 else 0\n",
    "    \n",
    "    # 定义召回率指标计算方式\n",
    "    def recall(self):\n",
    "        all, hit = 0, 0\n",
    "        for user in self.test:\n",
    "            test_users = set(self.test[user])\n",
    "            rank = self.recs[user]\n",
    "            for v, score in rank:\n",
    "                if v in test_users:\n",
    "                    hit += 1\n",
    "            all += len(test_users)\n",
    "        return round(hit / all * 100, 2) if all > 0 else 0\n",
    "    \n",
    "    def eval(self):\n",
    "        metric = {'Precision': self.precision(),\n",
    "                  'Recall': self.recall()}\n",
    "        print('Metric:', metric)\n",
    "        return metric"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 二. 算法实现\n",
    "主要是不同的用户相似度计算方法\n",
    "1. OUT\n",
    "2. IN\n",
    "3. OUT_IN\n",
    "4. OUT_IN_Cosine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1. 利用用户出度计算相似度\n",
    "def OUT(train, N):\n",
    "    '''\n",
    "    :params: train, 训练数据集（包含出和入的）\n",
    "    :params: N, 超参数，设置取TopN推荐用户数目\n",
    "    :return: GetRecommendation，推荐接口函数\n",
    "    '''\n",
    "    \n",
    "    G, GT = train\n",
    "    \n",
    "    def GetRecommendation(user):\n",
    "        if user not in G: return []\n",
    "        # 根据相似度推荐N个未见过的\n",
    "        user_sim = {}\n",
    "        user_friends = set(G[user])\n",
    "        for u in G[user]:\n",
    "            if u not in GT: continue\n",
    "            for v in GT[u]:\n",
    "                if v != user and v not in user_friends:\n",
    "                    if v not in user_sim:\n",
    "                        user_sim[v] = 0\n",
    "                    user_sim[v] += 1\n",
    "        user_sim = {v: user_sim[v] / math.sqrt(len(G[user] * len(G[v]))) for v in user_sim}\n",
    "        return list(sorted(user_sim.items(), key=lambda x: x[1], reverse=True))[:N]\n",
    "    \n",
    "    return GetRecommendation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2. 利用用户入度计算相似度\n",
    "def IN(train, N):\n",
    "    '''\n",
    "    :params: train, 训练数据集（包含出和入的）\n",
    "    :params: N, 超参数，设置取TopN推荐用户数目\n",
    "    :return: GetRecommendation，推荐接口函数\n",
    "    '''\n",
    "    \n",
    "    G, GT = train\n",
    "        \n",
    "    def GetRecommendation(user):\n",
    "        if user not in GT: return []\n",
    "        # 根据相似度推荐N个未见过的\n",
    "        user_sim = {}\n",
    "        user_friends = set(G[user]) if user in G else set()\n",
    "        for u in GT[user]:\n",
    "            if u not in G: continue\n",
    "            for v in G[u]:\n",
    "                if v != user and v not in user_friends:\n",
    "                    if v not in user_sim:\n",
    "                        user_sim[v] = 0\n",
    "                    user_sim[v] += 1\n",
    "        user_sim = {v: user_sim[v] / math.sqrt(len(GT[user] * len(GT[v]))) for v in user_sim}\n",
    "        return list(sorted(user_sim.items(), key=lambda x: x[1], reverse=True))[:N]\n",
    "    \n",
    "    return GetRecommendation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 3. 利用用户出度和入度进行计算，但没有考虑到热门入度用户的惩罚\n",
    "def OUT_IN(train, N):\n",
    "    '''\n",
    "    :params: train, 训练数据集（包含出和入的）\n",
    "    :params: N, 超参数，设置取TopN推荐用户数目\n",
    "    :return: GetRecommendation，推荐接口函数\n",
    "    '''\n",
    "    \n",
    "    G, GT = train\n",
    "    \n",
    "    def GetRecommendation(user):\n",
    "        if user not in G: return []\n",
    "        # 根据相似度推荐N个未见过的\n",
    "        user_sim = {}\n",
    "        user_friends = set(G[user])\n",
    "        for u in G[user]:\n",
    "            if u not in G: continue\n",
    "            for v in G[u]:\n",
    "                if v != user and v not in user_friends:\n",
    "                    if v not in user_sim:\n",
    "                        user_sim[v] = 0\n",
    "                    user_sim[v] += 1\n",
    "        user_sim = {v: user_sim[v] / len(G[user]) for v in user_sim}\n",
    "        return list(sorted(user_sim.items(), key=lambda x: x[1], reverse=True))[:N]\n",
    "    \n",
    "    return GetRecommendation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4. 利用用户出度和入度的余弦相似度进行计算\n",
    "def OUT_IN_Cosine(train, N):\n",
    "    '''\n",
    "    :params: train, 训练数据集（包含出和入的）\n",
    "    :params: N, 超参数，设置取TopN推荐用户数目\n",
    "    :return: GetRecommendation，推荐接口函数\n",
    "    '''\n",
    "    \n",
    "    G, GT = train\n",
    "    \n",
    "    def GetRecommendation(user):\n",
    "        if user not in G: return []\n",
    "        # 根据相似度推荐N个未见过的\n",
    "        user_sim = {}\n",
    "        user_friends = set(G[user])\n",
    "        for u in G[user]:\n",
    "            if u not in G: continue\n",
    "            for v in G[u]:\n",
    "                if v != user and v not in user_friends:\n",
    "                    if v not in user_sim:\n",
    "                        user_sim[v] = 0\n",
    "                    user_sim[v] += 1\n",
    "        user_sim = {v: user_sim[v] / math.sqrt(len(G[user]) * len(GT[v])) for v in user_sim}\n",
    "        return list(sorted(user_sim.items(), key=lambda x: x[1], reverse=True))[:N]\n",
    "    \n",
    "    return GetRecommendation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 三. 实验\n",
    "\n",
    "在两个数据集上进行实验，一个是Slashdot，一个是Epinions\n",
    "1. OUT实验\n",
    "2. IN实验\n",
    "3. OUT_IN实验\n",
    "4. OUT_IN_Cosine实验\n",
    "\n",
    "M=10, N=10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Experiment():\n",
    "    \n",
    "    def __init__(self, M, N, fp='../dataset/slashdot/soc-Slashdot0902.txt', rt='OUT'):\n",
    "        '''\n",
    "        :params: M, 进行多少次实验\n",
    "        :params: N, TopN推荐用户的个数\n",
    "        :params: fp, 数据文件路径\n",
    "        :params: rt, 推荐算法类型\n",
    "        '''\n",
    "        self.M = M\n",
    "        self.N = N\n",
    "        self.fp = fp\n",
    "        self.rt = rt\n",
    "        self.alg = {'OUT': OUT, 'IN': IN, \\\n",
    "                    'OUT_IN': OUT_IN, 'OUT_IN_Cosine': OUT_IN_Cosine}\n",
    "    \n",
    "    # 定义单次实验\n",
    "    def worker(self, train, test):\n",
    "        '''\n",
    "        :params: train, 训练数据集\n",
    "        :params: test, 测试数据集\n",
    "        :return: 各指标的值\n",
    "        '''\n",
    "        getRecommendation = self.alg[self.rt](train, self.N)\n",
    "        metric = Metric(train[0], test, getRecommendation)\n",
    "        return metric.eval()\n",
    "    \n",
    "    # 多次实验取平均\n",
    "    def run(self):\n",
    "        metrics = {'Precision': 0, 'Recall': 0}\n",
    "        dataset = Dataset(self.fp)\n",
    "        for ii in range(self.M):\n",
    "            train, test = dataset.splitData(self.M, ii)\n",
    "            print('Experiment {}:'.format(ii))\n",
    "            metric = self.worker(train, test)\n",
    "            metrics = {k: metrics[k]+metric[k] for k in metrics}\n",
    "        metrics = {k: metrics[k] / self.M for k in metrics}\n",
    "        print('Average Result (M={}, N={}, alg={}): {}'.format(\\\n",
    "                              self.M, self.N, self.rt, metrics))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Experiment 0:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.29}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.09, 'Recall': 0.41}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.09, 'Recall': 0.41}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.32}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.37}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
      "Average Result (M=10, N=10, alg=OUT): {'Precision': 0.077, 'Recall': 0.344}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.05, 'Recall': 0.2}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.05, 'Recall': 0.23}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.06, 'Recall': 0.25}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.04, 'Recall': 0.18}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.05, 'Recall': 0.21}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.32}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.05, 'Recall': 0.24}\n",
      "Average Result (M=10, N=10, alg=IN): {'Precision': 0.06000000000000001, 'Recall': 0.265}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.35}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.34}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.1, 'Recall': 0.43}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.08, 'Recall': 0.35}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.11, 'Recall': 0.49}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.06, 'Recall': 0.27}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.09, 'Recall': 0.37}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.07, 'Recall': 0.29}\n",
      "Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.081, 'Recall': 0.35}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.03, 'Recall': 0.11}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.09}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.03, 'Recall': 0.15}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.01, 'Recall': 0.06}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
      "Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.020999999999999998, 'Recall': 0.095}\n"
     ]
    }
   ],
   "source": [
    "# 1. Slashdot数据集实验\n",
    "M, N = 10, 10\n",
    "for alg in ['OUT', 'IN', 'OUT_IN', 'OUT_IN_Cosine']:\n",
    "    exp = Experiment(M, N, fp='../dataset/slashdot/soc-Slashdot0902.txt', rt=alg)\n",
    "    exp.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Experiment 0:\n",
      "Metric: {'Precision': 0.15, 'Recall': 0.63}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.21, 'Recall': 0.9}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.18, 'Recall': 0.79}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.16, 'Recall': 0.68}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.17, 'Recall': 0.73}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.19, 'Recall': 0.84}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.16, 'Recall': 0.67}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.17, 'Recall': 0.72}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.17, 'Recall': 0.73}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.19, 'Recall': 0.8}\n",
      "Average Result (M=10, N=10, alg=OUT): {'Precision': 0.175, 'Recall': 0.7489999999999999}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.2, 'Recall': 0.77}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.2, 'Recall': 0.78}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.25, 'Recall': 0.96}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.22, 'Recall': 0.85}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.19, 'Recall': 0.74}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.22, 'Recall': 0.83}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.23, 'Recall': 0.89}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.22, 'Recall': 0.85}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.19, 'Recall': 0.72}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.23, 'Recall': 0.88}\n",
      "Average Result (M=10, N=10, alg=IN): {'Precision': 0.215, 'Recall': 0.827}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.5, 'Recall': 2.13}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.53, 'Recall': 2.25}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.54, 'Recall': 2.26}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.52, 'Recall': 2.22}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.53, 'Recall': 2.24}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.59, 'Recall': 2.51}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.56, 'Recall': 2.37}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.55, 'Recall': 2.36}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.52, 'Recall': 2.21}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.56, 'Recall': 2.39}\n",
      "Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.54, 'Recall': 2.294}\n",
      "Experiment 0:\n",
      "Metric: {'Precision': 0.19, 'Recall': 0.82}\n",
      "Experiment 1:\n",
      "Metric: {'Precision': 0.21, 'Recall': 0.91}\n",
      "Experiment 2:\n",
      "Metric: {'Precision': 0.23, 'Recall': 0.96}\n",
      "Experiment 3:\n",
      "Metric: {'Precision': 0.26, 'Recall': 1.11}\n",
      "Experiment 4:\n",
      "Metric: {'Precision': 0.22, 'Recall': 0.94}\n",
      "Experiment 5:\n",
      "Metric: {'Precision': 0.26, 'Recall': 1.09}\n",
      "Experiment 6:\n",
      "Metric: {'Precision': 0.21, 'Recall': 0.9}\n",
      "Experiment 7:\n",
      "Metric: {'Precision': 0.24, 'Recall': 1.05}\n",
      "Experiment 8:\n",
      "Metric: {'Precision': 0.18, 'Recall': 0.79}\n",
      "Experiment 9:\n",
      "Metric: {'Precision': 0.23, 'Recall': 1.0}\n",
      "Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.223, 'Recall': 0.9570000000000001}\n"
     ]
    }
   ],
   "source": [
    "# 2. Epinions数据集实验\n",
    "M, N = 10, 10\n",
    "for alg in ['OUT', 'IN', 'OUT_IN', 'OUT_IN_Cosine']:\n",
    "    exp = Experiment(M, N, fp='../dataset/epinions/soc-Epinions1.txt', rt=alg)\n",
    "    exp.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 四. 实验结果\n",
    "\n",
    "1. Slashdot数据集实验\n",
    "\n",
    "    Average Result (M=10, N=10, alg=OUT): {'Precision': 0.077, 'Recall': 0.344}\n",
    "    \n",
    "    Average Result (M=10, N=10, alg=IN): {'Precision': 0.06, 'Recall': 0.265}\n",
    "    \n",
    "    Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.081, 'Recall': 0.35}\n",
    "    \n",
    "    Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.021, 'Recall': 0.095}\n",
    "    \n",
    "2. Epinions数据集实验\n",
    "\n",
    "    Average Result (M=10, N=10, alg=OUT): {'Precision': 0.175, 'Recall': 0.749}\n",
    "    \n",
    "    Average Result (M=10, N=10, alg=IN): {'Precision': 0.215, 'Recall': 0.827}\n",
    "    \n",
    "    Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.54, 'Recall': 2.294}\n",
    "\n",
    "    Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.223, 'Recall': 0.957}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 五. 总结\n",
    "1. 要注意会出现KeyError的情况，需常加判断，提升代码的鲁棒性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 附：运行日志（请双击看）\n",
    "\n",
    "1. Slashdot数据集实验\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.29}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.09, 'Recall': 0.41}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.09, 'Recall': 0.41}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.32}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.37}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
    "Average Result (M=10, N=10, alg=OUT): {'Precision': 0.077, 'Recall': 0.344}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.05, 'Recall': 0.2}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.05, 'Recall': 0.23}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.06, 'Recall': 0.25}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.36}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.04, 'Recall': 0.18}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.05, 'Recall': 0.21}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.32}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.05, 'Recall': 0.24}\n",
    "Average Result (M=10, N=10, alg=IN): {'Precision': 0.06000000000000001, 'Recall': 0.265}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.31}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.35}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.34}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.1, 'Recall': 0.43}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.08, 'Recall': 0.35}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.11, 'Recall': 0.49}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.06, 'Recall': 0.27}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.3}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.09, 'Recall': 0.37}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.07, 'Recall': 0.29}\n",
    "Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.081, 'Recall': 0.35}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.03, 'Recall': 0.11}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.09}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.03, 'Recall': 0.15}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.01, 'Recall': 0.06}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.1}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.02, 'Recall': 0.08}\n",
    "Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.020999999999999998, 'Recall': 0.095}\n",
    "\n",
    "2. Epinions数据集实验\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.15, 'Recall': 0.63}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.21, 'Recall': 0.9}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.18, 'Recall': 0.79}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.16, 'Recall': 0.68}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.17, 'Recall': 0.73}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.19, 'Recall': 0.84}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.16, 'Recall': 0.67}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.17, 'Recall': 0.72}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.17, 'Recall': 0.73}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.19, 'Recall': 0.8}\n",
    "Average Result (M=10, N=10, alg=OUT): {'Precision': 0.175, 'Recall': 0.7489999999999999}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.2, 'Recall': 0.77}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.2, 'Recall': 0.78}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.25, 'Recall': 0.96}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.22, 'Recall': 0.85}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.19, 'Recall': 0.74}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.22, 'Recall': 0.83}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.23, 'Recall': 0.89}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.22, 'Recall': 0.85}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.19, 'Recall': 0.72}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.23, 'Recall': 0.88}\n",
    "Average Result (M=10, N=10, alg=IN): {'Precision': 0.215, 'Recall': 0.827}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.5, 'Recall': 2.13}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.53, 'Recall': 2.25}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.54, 'Recall': 2.26}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.52, 'Recall': 2.22}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.53, 'Recall': 2.24}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.59, 'Recall': 2.51}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.56, 'Recall': 2.37}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.55, 'Recall': 2.36}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.52, 'Recall': 2.21}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.56, 'Recall': 2.39}\n",
    "Average Result (M=10, N=10, alg=OUT_IN): {'Precision': 0.54, 'Recall': 2.294}\n",
    "Experiment 0:\n",
    "Metric: {'Precision': 0.19, 'Recall': 0.82}\n",
    "Experiment 1:\n",
    "Metric: {'Precision': 0.21, 'Recall': 0.91}\n",
    "Experiment 2:\n",
    "Metric: {'Precision': 0.23, 'Recall': 0.96}\n",
    "Experiment 3:\n",
    "Metric: {'Precision': 0.26, 'Recall': 1.11}\n",
    "Experiment 4:\n",
    "Metric: {'Precision': 0.22, 'Recall': 0.94}\n",
    "Experiment 5:\n",
    "Metric: {'Precision': 0.26, 'Recall': 1.09}\n",
    "Experiment 6:\n",
    "Metric: {'Precision': 0.21, 'Recall': 0.9}\n",
    "Experiment 7:\n",
    "Metric: {'Precision': 0.24, 'Recall': 1.05}\n",
    "Experiment 8:\n",
    "Metric: {'Precision': 0.18, 'Recall': 0.79}\n",
    "Experiment 9:\n",
    "Metric: {'Precision': 0.23, 'Recall': 1.0}\n",
    "Average Result (M=10, N=10, alg=OUT_IN_Cosine): {'Precision': 0.223, 'Recall': 0.9570000000000001}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
